using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System.Globalization;
using System.Threading;
using System.Windows.Forms;
using System.Drawing;
using System.Text;

using Styx;
using Styx.CommonBot;
using Styx.CommonBot.Routines;
using Styx.Helpers;
using Styx.TreeSharp;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using Styx.Common.Helpers;
using Styx.Pathing;

using CommonBehaviors.Actions;

using Singular;
using Singular.Dynamics;
using Singular.Helpers;
using Singular.Managers;
using Singular.Settings;

using Action = Styx.TreeSharp.Action;
//
using Rest = Singular.Helpers.Rest;
//
using LocationRetriever = Singular.Helpers.LocationRetriever;

namespace Enh
{
    public class Routine : CombatRoutine
    {
        /// <summary>
        /// The name of this CombatRoutine
        /// </summary>
        /// <value>
        /// The name.
        /// </value>
        public override string Name { get { return "Enh"; } }


        /// <summary>
        /// The <see cref="T:Styx.WoWClass"/> to be used with this routine
        /// </summary>
        /// <value>
        /// The class.
        /// </value>
        public override WoWClass Class { get { return WoWClass.Shaman; } }


        private Composite _combat, _buffs;


        public override Composite CombatBehavior { get { return _combat; } }
        public override Composite PreCombatBuffBehavior { get { return _buffs; } }
        public override Composite CombatBuffBehavior { get { return _buffs; } }


        public override void Initialize()
        {
            _combat = CreateCombat();
            _buffs = CreateBuffs();
        }

		private bool IsTargetBoss()
        {
            if (StyxWoW.Me.CurrentTarget.CreatureRank == WoWUnitClassificationType.WorldBoss ||
               (StyxWoW.Me.CurrentTarget.Level >= 85 && StyxWoW.Me.CurrentTarget.Elite && StyxWoW.Me.CurrentTarget.MaxHealth > 6000000))
                return true;

            else return false;
        }
		
		private int addCount()
        {
            int count = 0;
            foreach (WoWUnit u in ObjectManager.GetObjectsOfType<WoWUnit>(true, true))
            {
                if (u.IsAlive
                    && StyxWoW.Me.CurrentTarget != null
                    && u.Guid != StyxWoW.Me.Guid
                    && !u.IsFriendly
                    && (u.IsHostile || u.IsNeutral)
                    && !u.IsCritter
                    && u.Location.Distance(StyxWoW.Me.Location) <= 20
                    && (u.IsTargetingMyPartyMember || u.IsTargetingMyRaidMember || u.IsTargetingMeOrPet || u.IsTargetingAnyMinion))
                {
                    count++;
                }
            }
            return count;
        }

        private int RAOEaddCount()
        {
            int count = 0;
            foreach (WoWUnit u in ObjectManager.GetObjectsOfType<WoWUnit>(true, true))
            {
                if (u.IsAlive
                    && StyxWoW.Me.CurrentTarget != null
                    && u.Guid != StyxWoW.Me.Guid
                    && !u.IsFriendly
                    && (u.IsHostile || u.IsNeutral)
                    && !u.IsCritter
                    && u.Location.Distance(StyxWoW.Me.CurrentTarget.Location) <= 15//&& u.IsWithinMeleeRange
                    && (u.IsTargetingMyPartyMember || u.IsTargetingMyRaidMember || u.IsTargetingMeOrPet || u.IsTargetingAnyMinion))
                {
                    count++;
                }
            }
            return count;
        }

        Composite CreateBuffs()
        {
            return new PrioritySelector(
				Cast("Lightning Shield", ret => ! StyxWoW.Me.HasAura("Lightning Shield") && !StyxWoW.Me.Mounted),
				new Decorator(ret => StyxWoW.Me.Inventory.Equipped.MainHand.TemporaryEnchantment.Id != 283,  
					new Sequence( 
						new Action(ctx => Lua.DoString("CancelItemTempEnchantment(1)")),
						Cast("Windfury Weapon")
					)
				),

				new Decorator(ret => StyxWoW.Me.Inventory.Equipped.OffHand.ItemInfo.ItemClass == WoWItemClass.Weapon,
					new Decorator(ret => StyxWoW.Me.Inventory.Equipped.OffHand.TemporaryEnchantment.Id != 5,  
						new Sequence( 
							new Action(ctx => Lua.DoString("CancelItemTempEnchantment(2)")),
							Cast("Flametongue Weapon")
						)
					)
				),
				
				new Decorator(ret =>
					!(StyxWoW.Me.HasAura("Visions of Insanity") || StyxWoW.Me.HasAura("Enhanced Agility")) && !StyxWoW.Me.Mounted,
					new Action(abc =>
					{
						WoWItem item = StyxWoW.Me.BagItems.Find(ret => ret.Name == "Crystal of Insanity"); //ret.Entry == 86569);
                        if (item != null) 
						{
								item.Use();
						}
						else 
						{
							WoWItem item2 = StyxWoW.Me.BagItems.Find(ret => ret.Name == "Alchemist's Flask");
							if (item2 != null) item2.Use();
						}; 
					})
				)
/*				
				new Decorator(ret =>
					!StyxWoW.Me.HasAura("Enhanced Agility") && !StyxWoW.Me.Mounted,
					new Action(abc =>
					{
						WoWItem item = StyxWoW.Me.BagItems.Find(ret => ret.Entry == 75525);
                            if (item != null) item.Use(); 
					})
				)
*/
			);
        }


        Composite CreateCombat()
        {
			return new Decorator ( ctz => !StyxWoW.Me.Mounted && !StyxWoW.Me.HasAura("Drink") && !StyxWoW.Me.HasAura("Food") && !StyxWoW.Me.HasAura("First Aid"),
				new PrioritySelector(
                // Interrupt please.
                Cast("Wind Shear", ret => StyxWoW.Me.CurrentTarget.IsCasting && StyxWoW.Me.CurrentTarget.CanInterruptCurrentSpellCast),

				new Decorator(ret => StyxWoW.Me.Inventory.Equipped.MainHand.TemporaryEnchantment.Id != 283,  
					new Sequence( 
						new Action(ctx => Lua.DoString("CancelItemTempEnchantment(1)")),
						Cast("Windfury Weapon")
					)
				),

				new Decorator(ret => StyxWoW.Me.Inventory.Equipped.OffHand.ItemInfo.ItemClass == WoWItemClass.Weapon,
					new Decorator(ret => StyxWoW.Me.Inventory.Equipped.OffHand.TemporaryEnchantment.Id != 5,  
						new Sequence( 
							new Action(ctx => Lua.DoString("CancelItemTempEnchantment(2)")),
							Cast("Flametongue Weapon")
						)
					)
				),

				//Cast("Windfury Weapon", ret => !StyxWoW.Me.HasAura("Windfury Weapon")),
				//Cast("Flametongue Weapon", ret => !StyxWoW.Me.HasAura("Flametongue Weapon")),
				Cast("Lightning Shield", ret => !StyxWoW.Me.HasAura("Lightning Shield")),

				// Defensive/Healing CD
				Cast("Healing Surge", ret => StyxWoW.Me.HealthPercent < 65 && StyxWoW.Me.Auras["Maelstrom Weapon"].StackCount > 4),
				Cast("Healing Surge", ret => StyxWoW.Me.HealthPercent < 65 && StyxWoW.Me.HasAura("Maelstrom Weapon", 5)),
				Cast("Healing Surge", ret => StyxWoW.Me.HealthPercent < 40),
				Cast("Ancestral Guidance", ret => StyxWoW.Me.HealthPercent < 50),
				Cast("Shamanistic Rage", ret => StyxWoW.Me.HealthPercent < 75),
				Cast("Astral Shift", ret => StyxWoW.Me.HealthPercent < 85),

                new Action(ret => { UseTrinkets(); return RunStatus.Failure; }),
				Cast("Lifeblood"),
				
//                new Decorator(ret => addCount() > 2,
//                    CreateAoe()),

			new Decorator ( cts => addCount() > 2,
				new PrioritySelector(
			    Spell.Cast("Magma Totem", ret => StyxWoW.Me.Totems.Count(t => t.WoWTotem == WoWTotem.Magma && t.Unit.Distance < 8 && t.WoWTotem != WoWTotem.FireElemental) == 0 && addCount() > 3),	
				//Spell.Cast("Feral Spirit"),
				Spell.Cast("Flame Shock", ret => (!StyxWoW.Me.CurrentTarget.HasMyAura("Flame Shock") ||
					StyxWoW.Me.CurrentTarget.ActiveAuras["Flame Shock"].TimeLeft.TotalSeconds <= 3)),
				Spell.Cast("Lava Lash"), //ret => StyxWoW.Me.CurrentTarget.HasMyAura("Flame Shock")),
                Spell.Cast("Fire Nova"), //ret => addCount() > 2 && StyxWoW.Me.CurrentTarget.HasMyAura("Flame Shock")),
				//Spell.Cast("Flame Shock", ret => StyxWoW.Me.HasAura("Unleash Flame")),
                Spell.Cast("Chain Lightning", ret => RAOEaddCount() > 1 && StyxWoW.Me.Auras["Maelstrom Weapon"].StackCount > 4),
				Spell.Cast("Chain Lightning", ret => RAOEaddCount() > 1 && StyxWoW.Me.HasAura("Maelstrom Weapon", 5)),
				Spell.Cast("Unleash Elements")
				
                //Cast("Chain Lightning",
                //    ret => Clusters.GetClusterCount(StyxWoW.Me.CurrentTarget, Unit.NearbyUnfriendlyUnits, ClusterType.Chained, 10f) >= 2 &&
                //        StyxWoW.Me.Auras["Maelstrom Weapon"].StackCount > 4),
                // Cast("Fire Nova",
                //    ret => Clusters.GetClusterCount(StyxWoW.Me.CurrentTarget, Unit.NearbyUnfriendlyUnits, ClusterType.Radius, 10f) >= 2 &&
                //           StyxWoW.Me.CurrentTarget.HasMyAura("Flame Shock"))

						   
                )),


/*
				Cast("Searing Totem", ret => !StyxWoW.Me.IsMoving && 
					StyxWoW.Me.CurrentTarget.Distance < (15 + Spell.SafeMeleeRange) &&
                    StyxWoW.Me.Totems.Count(t => t.WoWTotem == WoWTotem.Searing && 
						t.Unit.Distance < StyxWoW.Me.Totems.GetTotemRange(WoWTotem.Searing)) == 0),
*/
				//Cast("Searing Totem", ret => StyxWoW.Me.Totems.Count(t =>
                //    t.Unit != null && t.WoWTotem == WoWTotem.Searing &&
                //    t.Unit.Location.DistanceSqr(StyxWoW.Me.CurrentTarget.Location) < 25 * 25) == 0 &&
                //    !StyxWoW.Me.Totems.Any(t => t.WoWTotem == WoWTotem.FireElemental)),
				Spell.Cast("Searing Totem", ret => StyxWoW.Me.Totems.Count(t => t.WoWTotem == WoWTotem.Searing && t.Unit.Distance < 20 && t.WoWTotem != WoWTotem.FireElemental) == 0),	
				//Spell.Cast("Fire Elemental Totem", ret => StyxWoW.Me, ret => StyxWoW.Me.CurrentTarget.IsBoss && !StyxWoW.Me.Totems.Any(t => t.WoWTotem == WoWTotem.FireElemental)),
				Spell.Cast("Feral Spirit", ret => IsTargetBoss()),
				Spell.Cast("Ascendance", ret => IsTargetBoss()),
				Spell.Cast("Flame Shock", ret => StyxWoW.Me.HasAura("Unleash Flame")),
				Spell.Cast("Unleash Elements"),
				Spell.Cast("Flame Shock", ret => !StyxWoW.Me.CurrentTarget.HasMyAura("Flame Shock") ||
					StyxWoW.Me.CurrentTarget.ActiveAuras["Flame Shock"].TimeLeft.TotalSeconds < 7),
				
				Spell.Cast("Lightning Bolt", ret => StyxWoW.Me.Auras["Maelstrom Weapon"].StackCount > 4),
				Spell.Cast("Lightning Bolt", ret => StyxWoW.Me.HasAura("Maelstrom Weapon", 5)),
				Spell.Cast("Stormstrike"),
				Spell.Cast("Stormblast"),
				Spell.Cast("Lava Lash"),
				Spell.Cast("Earth Shock")
			));
        }
		
        Composite CreateAoe()
        {
            return new PrioritySelector(
                //Cast("Dragon Roar"),
                //Cast("Gorefiend's Grasp", ret => TalentManager.IsSelected((int)Common.DeathKnightTalents.GorefiendsGrasp)),
                //Cast("Remorseless Winter", ret => TalentManager.IsSelected((int)Common.DeathKnightTalents.RemoreselessWinter)),
				//BuffSelf("Unholy Blight", ret =>
                //                       TalentManager.IsSelected((int)Common.DeathKnightTalents.UnholyBlight) &&
                //                       StyxWoW.Me.CurrentTarget.DistanceSqr <= 10 * 10 &&
                //                       !StyxWoW.Me.HasAura("Unholy Blight")),

			    Spell.Cast("Magma Totem", ret => StyxWoW.Me.Totems.Count(t => t.WoWTotem == WoWTotem.Magma && t.Unit.Distance < 8 && t.WoWTotem != WoWTotem.FireElemental) == 0),	
				Spell.Cast("Feral Spirit"),
				Spell.Cast("Flame Shock", ret => StyxWoW.Me.HasAura("Unleash Flame")),
				Spell.Cast("Unleash Elements"),
				Spell.Cast("Flame Shock", ret => !StyxWoW.Me.CurrentTarget.HasMyAura("Flame Shock") ||
					StyxWoW.Me.CurrentTarget.ActiveAuras["Flame Shock"].TimeLeft.TotalSeconds < 5),
				Spell.Cast("Lava lash", ret => StyxWoW.Me.CurrentTarget.HasMyAura("Flame Shock")),
                Spell.Cast("Chain Lightning", ret => RAOEaddCount() > 1 && StyxWoW.Me.Auras["Maelstrom Weapon"].StackCount > 4),
                //Cast("Chain Lightning",
                //    ret => Clusters.GetClusterCount(StyxWoW.Me.CurrentTarget, Unit.NearbyUnfriendlyUnits, ClusterType.Chained, 10f) >= 2 &&
                //        StyxWoW.Me.Auras["Maelstrom Weapon"].StackCount > 4),
                Spell.Cast("Fire Nova", ret => addCount() > 2 && StyxWoW.Me.CurrentTarget.HasMyAura("Flame Shock"))
                // Cast("Fire Nova",
                //    ret => Clusters.GetClusterCount(StyxWoW.Me.CurrentTarget, Unit.NearbyUnfriendlyUnits, ClusterType.Radius, 10f) >= 2 &&
                //           StyxWoW.Me.CurrentTarget.HasMyAura("Flame Shock"))

						   
                );
        }


        void UseTrinkets()
        {
            var firstTrinket = StyxWoW.Me.Inventory.Equipped.Trinket1;
            var secondTrinket = StyxWoW.Me.Inventory.Equipped.Trinket2;


            if(firstTrinket != null && CanUseEquippedItem(firstTrinket))
                firstTrinket.Use();


            if(secondTrinket != null && CanUseEquippedItem(secondTrinket))
                secondTrinket.Use();


        }
        private static bool CanUseEquippedItem(WoWItem item)
        {
            // Check for engineering tinkers!
            string itemSpell = Lua.GetReturnVal<string>("return GetItemSpell(" + item.Entry + ")", 0);
            if (string.IsNullOrEmpty(itemSpell))
                return false;


            return item.Usable && item.Cooldown <= 0;
        }


        IEnumerable<WoWUnit> UnfriendlyUnits
        {
            get { return ObjectManager.GetObjectsOfType<WoWUnit>(true, false).Where(u => !u.IsDead && u.CanSelect && u.Attackable && !u.IsFriendly && u.IsWithinMeleeRange); }
        }


        //bool NeedRunicDump
        //{
        //    get
        //    {
                // Flat out, drop HS if we need to.
        //        if (StyxWoW.Me.RunicPowerPercent >= 90)
        //            return true;
        //    }
        //}


        private delegate T Selection<out T>(object context);
        Composite Cast(string spell, Selection<bool> reqs = null)
        {
            return
                new Decorator(
                    ret => ((reqs != null && reqs(ret)) || (reqs == null)) && SpellManager.CanCast(spell),
                    new Action(ret => SpellManager.Cast(spell)));
        }


        public static TimeSpan GetSpellCooldown(string spell)
        {
            SpellFindResults results;
            if (SpellManager.FindSpell(spell, out results))
            {
                if (results.Override != null)
                    return results.Override.CooldownTimeLeft;
                return results.Original.CooldownTimeLeft;
            }


            return TimeSpan.MaxValue;
        }
    }
}